#pragma once

typedef CXTShellPidl::CShellMalloc CShellMalloc;

//class CShellMalloc
//{
//public:
//	CShellMalloc()
//	{
//		m_lpMalloc = NULL;
//
//		if(FAILED(::SHGetMalloc(&m_lpMalloc)))
//			m_lpMalloc = NULL;
//	}
//
//	~CShellMalloc()
//	{
//		if(m_lpMalloc)
//			m_lpMalloc->Release();
//	}
//
//	void* Alloc(DWORD nBytes)
//	{
//		ASSERT(m_lpMalloc != NULL);
//		return m_lpMalloc ? m_lpMalloc->Alloc(nBytes) : NULL;
//	}
//
//	void Free(void* lpMem)
//	{
//		ASSERT(m_lpMalloc != NULL);
//		if (m_lpMalloc)
//		{
//			m_lpMalloc->Free(lpMem);
//		}
//	}
//
//	operator LPMALLOC()
//	{
//		return m_lpMalloc;
//	}
//
//protected:
//	LPMALLOC m_lpMalloc;
//};

class CShellSpecialFolder
{
public:
	CShellSpecialFolder(int nFolder = CSIDL_DESKTOP, CShellMalloc* pShellMalloc = NULL)
	{
		m_lpFolder = NULL;

		if(FAILED(::SHGetDesktopFolder(&m_lpFolder)))
		{
			m_lpFolder = NULL;
			return;
		}

		if(nFolder != CSIDL_DESKTOP)
		{
			LPSHELLFOLDER lpFolder = NULL;

			if(pShellMalloc == NULL)
			{
				CShellMalloc shMalloc;
				if(shMalloc != NULL)
				{
					LPITEMIDLIST pidlFolder = NULL;
					if(SUCCEEDED(::SHGetSpecialFolderLocation(NULL, nFolder, &pidlFolder)))
					{
						m_lpFolder->BindToObject(pidlFolder, 0, IID_IShellFolder, (LPVOID*)&lpFolder);
						shMalloc.Free(pidlFolder);
					}
				}
			}
			else
			{
				LPITEMIDLIST pidlFolder = NULL;
				if(SUCCEEDED(::SHGetSpecialFolderLocation(NULL, nFolder, &pidlFolder)))
				{
					m_lpFolder->BindToObject(pidlFolder, 0, IID_IShellFolder, (LPVOID*)&lpFolder);
					pShellMalloc->Free(pidlFolder);
				}
			}

			m_lpFolder->Release();
			m_lpFolder = lpFolder;
		}
	}

	~CShellSpecialFolder()
	{
		if(m_lpFolder != NULL)
		{
			m_lpFolder->Release();
		}
	}

	operator LPSHELLFOLDER()
	{
		return m_lpFolder;
	}

protected:
	LPSHELLFOLDER m_lpFolder;
};

class CItemIDList
{	
public:
	CItemIDList(CShellMalloc* pShellMalloc = NULL);
	CItemIDList(const CString& strPathName, CShellMalloc* pShellMalloc = NULL);
	CItemIDList(LPITEMIDLIST pidlFullyQual, bool bWrap = false, CShellMalloc* pShellMalloc = NULL);
	CItemIDList(const CItemIDList& other);
	virtual ~CItemIDList(void);

public:
	bool operator==(const CItemIDList& other);
	bool operator==(LPITEMIDLIST pidlFullyQual);
	const CItemIDList& operator=(const CString& strPathName);
	const CItemIDList& operator=(LPITEMIDLIST pidlFullyQual);
	const CItemIDList& operator=(const CItemIDList& other);
	operator LPITEMIDLIST() const;
	LPITEMIDLIST operator ->();
	
public:
	const CItemIDList& Attach(LPITEMIDLIST lpIDList);
	LPITEMIDLIST Detach();
	void Move(CItemIDList& other);

public:
	UINT GetItemCount(LPITEMIDLIST lpIDList = NULL);
	UINT GetTotalSize(LPITEMIDLIST lpIDList = NULL);
	bool IsDesktop(LPITEMIDLIST pidlFullQual = NULL);
	LPITEMIDLIST Up(LPITEMIDLIST pidlFullQual = NULL);
	
public:
	CString GetName();
	CString GetPath();
	const CString& GetName(CString& strName);
	const CString& GetPath(CString& strPath);
	BOOL GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST  lpIDList, DWORD dwFlags, CString& lpFriendlyName);
	
protected:
	LPITEMIDLIST CreateIDList(LPMALLOC lpMalloc, UINT cbSize);
	LPITEMIDLIST GetLastItem(LPITEMIDLIST lpIDList);
	LPITEMIDLIST GetNextItem(LPITEMIDLIST lpIDList);
	void FreeIDList();
	
protected:
	bool		 m_bWrap;
	CShellMalloc* m_pShellMalloc;
	LPITEMIDLIST m_pItemIDList;
};
